
This project contains alternative firmware for the Digirule 2 by Brad Slattery

Brad's original firmware, written in Swordfish BASIC, is open source and available
for download from his website (bradsprojects.com/digirule2).  To compile it
requires the Swordfish BASIC compiler (www.sfcompiler.co.uk).  Although a free
Special Edition of the Swordfish compiler is available, it places a limit on the
amount of RAM available to user programs, and the Digirule 2 sources exceed that
limit.  Therefore the full version of the compiler is required to compile the
sources.  At last check, the cost of that compiler was 99.95, or about $130 USD,
a price which may be out of reach for many users.

In an effort to foster further experimentation with the Digirule 2 and expand it to
an even wider audience, I decided to embark on a project to write an alternative
set of firmware for it, written in C, that would provide essentially the same
functionality as Brad's original BASIC firmware.  This project can be compiled
using the free cross-platform MPLAB X IDE and XC8 compiler from Microchip
Technology (www.microchip.com).

I made an effort to maintain instruction set compatibility with Brad's original
firmware, while also providing a few enhancements to the CPU and user interface.
For a list of differences and enhancements, please see below.

My thanks to Brad for designing the thoroughly fun-to-use Digirule 2, and for
his encouragement and support of this development project.

Brent Hauser / KD0GLS, December 2018

===============================================================================

Functional differences between this firmware and the original firmware:

* The SPEED instruction has been changed with regard to the way the parameter
  is interpreted.  A parameter value of 0 selects the maximum (unregulated)
  execution rate of approximately 18000 instructions per second.  All other
  parameter values select regulated instruction execution rates ranging from
  1 to 1000 instructions per second, on a logarithmic scale.  As before, the
  higher the value, the lower the rate.  Note that regulation affects only
  when the next instruction is started, not how quickly it executes.  Once
  started, an instruction always executes at maximum speed.

* The ADDRPC instruction has been changed with regard to the value contained
  in the program counter prior to the addition of the value contained in RAM.
  The program counter now contains the address of the next instruction when
  the addition takes place, such that an addition value of 0 will have no
  effect on the program counter, resulting in the next sequential instruction
  being executed.  This matches the behavior described in the User Manual.
  In the original firmware, the program counter contained the address of the
  ADDRPC instruction itself when the addition took place, such that an
  addition value of 2 resulted in the next sequential instruction being
  executed.  An addition value of 0 resulted in an infinite loop.  A build
  option is provided to obtain the original behavior if desired.  Note that
  sample program 1 (which uses the ADDRPC instruction) will be compiled
  accordingly so that it runs correctly with either build option setting.
  
* The CPU call/return stack is now four levels deep.  The internal stack
  pointer is automatically initialized whenever a program is loaded.  Also,
  new instruction INITSP (opcode 33) may be used to explicitly initialize
  the stack pointer, such as at the beginning of a program.  This will
  ensure the stack will not overflow if the program is restarted.  The CPU
  will halt on a stack overflow or underflow.

* New instruction RANDA (opcode 34) stores a pseudo-random number
  (1 to 255) in the accumulator.

* The CPU will halt if it fetches an instruction with an unknown opcode.

* The code is now highly responsive to user button input, even when the CPU
  instruction execution rate is very low.

* While holding down the Load button, pressing the Run/Stop button resets
  the CPU.  This may be useful to reset the internal stack pointer before
  restarting a program that doesn't explicitly use the INITSP instruction.
  Note the CPU is automatically reset whenever a program is loaded.

* While holding down the Load button, pressing the Prev button clears all
  of RAM (effectively loading an empty program) and resets the CPU.

* When entering data into the Data LEDs, holding down the Data 7 button
  for one second will set all bits, and holding down the Data 0 button
  for one second will clear all bits.

* On a Save operation, the registers at the upper end of the RAM address space
  are always saved as 0xFF, regardless of their actual contents.  On a Load
  operation, those registers are loaded with 0, and the CPU is reset (so you
  can simply Load and Run).

* A progress bar is displayed on the address LEDs during a Load or Save operation.

* The power-on LED animation is different.

* Unused PIC I/O pins are programmed as outputs, so they don't float.
